/*!
 * vinculum
 * Copyright(c) 2017 azzly
 * MIT Licensed
 */
 
'use strict';

/**
 * Module dependencies.
 * @private
 */
const cronJob = require('cron').CronJob; 
 
const helper = require("./helper");
const CONST = require("./CONST");
const config = require("./config");
const debug = require("./debug")(__filename);
const datasource = require("./datasource");
const action = require("./oo/action");
const service = require("./oo/service");


/**
 * Variables
 * @private
 */

let jobkeys = {};
let _isstarted = false;

function insertlog(cron_name,excute_params,islog,rp){
	if(islog === CONST.LOG_TYPES.LOG){
		let log_params = [
			helper.uuid()
			,cron_name
			,'cron'
			,null
			,null
			,helper.json2string(excute_params)
			,helper.json2string(rp)
		];
		datasource.systemQuery(CONST.SQLS.log_insert,log_params);
	}
}
 
/**
 * class.
 **/
class oneCron{
  constructor(cron_name,cron_time,excute_type,action_name,service_name,excute_params,islog){
    excute_params = helper.string2json(excute_params) || {};

    this.running = false;
    this.cronJob = new cronJob({
      cronTime: cron_time,
      onTick: ()=> {
        debug(`excute cron:${cron_name} begin`);
				let presult;
        if(excute_type === 'action'){
          presult = new action(action_name).excute(excute_params);
        }else if(excute_type === 'service'){
          presult = new service(service_name).invoke(excute_params);
        }
				if(presult) {
					presult.then(result=>{
						insertlog(cron_name,excute_params,islog,result);
					}).catch(err=>{
						insertlog(cron_name,excute_params,islog,err);
					});
				}
      },
      onComplete:()=>{
        insertlog(cron_name,cron_time,excute_params,islog,'complete');
        this.running = false;
      },
      start: false
      //,timeZone: 'America/Los_Angeles'
    });
    this.start();
  }
  
  stop(){
    if(this.running && this.cronJob) {
      this.cronJob.stop();
      this.running = false;
    }else{
      debug(this.id,this.action_name,this.cron_time,' has stoped');
    }
  }
  
  start(){
    if(this.running){
      debug(this.id,this.action_name,this.cron_time,' is running');
      return;
    }
    
    if(this.cronJob){
      this.running = true;
      this.cronJob.start();
    }
  }
}

/**
 * prototype.
 */

let obj = exports = module.exports = {};

/**
 * start
 *
 * @public
 */
 
obj.start = function(){
  if(_isstarted){
		debug('already start');
	}else{
		_isstarted = true;
		datasource.systemQuery(CONST.SQLS.cron_list).then(result=>{
			if(result.length === 0){
				_isstarted = false;
				debug(`no cron need run!`);
				return;
			}
			for(let i=0,len=result.length;i<len;i++){
				let one = result[i];
				let id = one.id;
				let cron_time = one.cron_time;
				let service_name = one.service_name;
				let action_name = one.action_name;
				let cron_name = one.cron_name;
				let excute_type = one.excute_type;
				let excute_params = one.excute_params;
				let islog = one.islog;
				if(jobkeys[id]){
					debug('already in jobs: ',cron_name);
				}else{
					debug(`add cron: ${cron_name},cron_time: ${cron_time},service_name: ${service_name},action_name: ${action_name}`);
					jobkeys[id] = new oneCron(cron_name,cron_time,excute_type,action_name,service_name,excute_params,islog);
				}
			}
		}).catch(err=>{
			console.error(err);
		});
	}
};

/**
 * stop
 *
 * @public
 */
 
obj.stop = function(){
  if(_isstarted){
		let keys = Object.keys(jobkeys);
		for(let i=0,len=keys.length;i<len;i++){
				let key = keys[i];
				let one = jobkeys[key];
				one.stop();
				jobkeys[key] = null;
		}
		jobkeys = [];
		_isstarted = false;
	}else{
		debug('already stoped');
	}
};